#ifndef TIEC_SYMBOL_H
#define TIEC_SYMBOL_H

#include "macro.h"
#include "foundation.h"
#include "data.h"

namespace NS_TIEC {

#define DECL_MODIFIER(name, value) static constexpr int64_t name = value;
  /// 修饰符类
  class Modifiers {
  public:
    DECL_MODIFIER(kStatic, 1)
    DECL_MODIFIER(kPublic, kStatic << 1)
    DECL_MODIFIER(kPrivate, kPublic << 1)
    DECL_MODIFIER(kConst, kPrivate << 1)
    DECL_MODIFIER(kVirtualMethod, kConst << 1)
    DECL_MODIFIER(kVirtualEvent, kVirtualMethod << 1)
    DECL_MODIFIER(kForceOutput, kVirtualEvent << 1)
    DECL_MODIFIER(kForbidNew, kForceOutput << 1)
    DECL_MODIFIER(kForbidOutput, kForbidNew << 1)
    DECL_MODIFIER(kGlobalClass, kForbidOutput << 1)
    DECL_MODIFIER(kInline, kGlobalClass << 1)
    DECL_MODIFIER(kDebug, kInline << 1)
    DECL_MODIFIER(kNullable, kDebug << 1)
    DECL_MODIFIER(kOperatorOverload, kNullable << 1)
    DECL_MODIFIER(kAutoSubscribe, kOperatorOverload << 1)
    DECL_MODIFIER(kAsyncMethod, kAutoSubscribe << 1)
    DECL_MODIFIER(kDeprecated, kAsyncMethod << 1)
    constexpr static Int64 kLevelPackage = 1;
    constexpr static Int64 kLevelClass = kLevelPackage << 1;
    constexpr static Int64 kLevelMethod = kLevelClass << 1;
    constexpr static Int64 kLevelEvent = kLevelMethod << 1;
    constexpr static Int64 kLevelVariable = kLevelEvent << 1;

    Modifiers();
    explicit Modifiers(Int64 modifier);

    /// 添加一个修饰符
    /// \param modifier 修饰符
    void add(Int64 modifier);

    /// 添加一个修饰符
    /// \param modifier 修饰符
    void operator<<(Int64 modifier);

    /// 移除一个修饰符
    /// \param modifier 修饰符
    void remove(Int64 modifier);

    /// 判断是否包含某个修饰符
    /// \param modifier 修饰符
    bool has(Int64 modifier) const;

    String toString() const;

  private:
    Int64 modifier_;
  };
#undef DECL_MODIFIER

  enum struct TypeKind {
    kClass = 0,
    kArray,
    kTemplate,
    kTypeVariable,
    kVariant,
    kVoid,
    kNull
  };

  class Type {
  public:
    virtual TypeKind getKind() = 0;
  };

  enum struct SymbolKind {
    kPackage = 0,
    kClass,
    kTypeVar,
    kVariable,
    kMethod,
    kEvent,
  };

  /// Symbol包含的自定义数据
  struct SymbolData {
    List<PAIR<PTR<Name>, ConstValue>> values;

    void addValue(const PTR<Name>& name, const ConstValue& value);
    bool hasValue(const PTR<Name>& name) const;
    ConstValue findValue(const PTR<Name>& name) const;
  };

  /// Symbol输出的配置
  struct OutputConfig {
    WString output_name;
    bool is_analyzed {false};
  };

  /// Symbol进行符号填充时的状态
  enum struct CompleteStatus {
    /// 初始状态
    kReady = 0,
    /// 等待依赖的Symbol先填充
    kPending,
    /// 填充完毕
    kDone
  };

  class Symbol {
  public:
    PTR<Name> name;
    Modifiers modifiers;
    WPTR<Symbol> owner;
    PTR<Type> type;
    Origin origin;
    SymbolData data;
    OutputConfig output_config;
    CompleteStatus status {CompleteStatus::kReady};

    virtual SymbolKind getKind() = 0;
  };

  class Scope {
  public:
    /// 获取作用域下所有符号
    /// @param recursive 是否递归获取
    virtual List<PTR<Symbol>> getSymbols(const bool recursive = false);

    /// 过滤作用域下所有符号
    /// @param recursive 是否递归获取
    virtual List<PTR<Symbol>> getSymbols(FUNCTION<bool(const PTR<Symbol>&)> filter, const bool recursive = false);

    /// 获取作用域下指定名称的符号
    /// @param name 符号名称
    /// @param recursive 是否递归获取
    virtual List<PTR<Symbol>> getSymbolsByName(const PTR<Name>& name, const bool recursive = true);

    /// 获取作用域下指定名称的符号
    /// @param name 符号名称
    /// @param filter 过滤函数
    /// @param recursive 是否递归获取
    virtual List<PTR<Symbol>> getSymbolsByName(const PTR<Name>& name, FUNCTION<bool(const PTR<Symbol>&)> filter, const bool recursive = true);

    /// 根据名称获取作用域下名称匹配的第一个符号
    /// @param name 名称
    /// @param recursive 是否递归获取
    virtual PTR<Symbol> getFirstByName(const PTR<Name>& name, const bool recursive = true);

    /// 根据名称获取作用域下名称匹配的第一个符号
    /// @param name 名称
    /// @param filter 过滤函数
    /// @param recursive 是否递归获取
    virtual PTR<Symbol> getFirstByName(const PTR<Name>& name, FUNCTION<bool(const PTR<Symbol>&)> filter, const bool recursive = true);

    /// 判断当前作用域下是否包含指定Symbol
    /// @param symbol 传入的Symbol
    virtual bool contains(const PTR<Symbol>& symbol);

    /// 判断当前作用域下是否有符合条件的Symbol
    /// @param filter 过滤条件
    virtual bool containsIf(FUNCTION<bool(const PTR<Symbol>&)> filter);

    /// 当前作用域符号是否为空
    virtual bool isEmpty() const;
  protected:
    List<PTR<Symbol>> symbols_;
    WPTR<Scope> parent_;
  };

  class MutableScope : public Scope {
  public:
    /// 设置当前作用域的父级作用域
    /// @param parent 父级节点
    void setParent(const PTR<MutableScope>& parent);

    /// 在当前作用域下添加一个Symbol
    /// @param symbol 要添加的Symbol
    void addSymbol(const PTR<Symbol>& symbol);

    /// 在当前作用域下移除一个Symbol
    /// @param symbol 要移除的Symbol
    void removeSymbol(const PTR<Symbol>& symbol);
  };

  class PackageSymbol : public Symbol {
  public:
    SymbolKind getKind() override;
  };

  class TypeVarSymbol : public Symbol {
  public:
    SymbolKind getKind() override;
  };

  class ClassSymbol : public Symbol {
  public:
    /// 完整类名（包含包名）
    PTR<Name> full_name;
    /// 模板类型参数
    List<PTR<Symbol>> params;
    /// 成员
    PTR<MutableScope> members;
    /// 父类
    PTR<ClassSymbol> super;
    /// 常量类型
    PTR<Type> const_type;
    /// 需求值类型（除了基本类型之外，可能还为文件路径或者颜色值，就看SymbolData有没有key为文件路径或者颜色值）
    PTR<Type> expected_type;
    /// 值输出规则名称
    PTR<Name> value_rule_name;

    SymbolKind getKind() override;

    PTR<Name> getPackageName() const;

    bool isTemplateClass() const;
  };

  class VarSymbol : public Symbol {
  public:
    bool is_parameter;
    List<PTR<Symbol>> used_symbols;
    /// 常量值
    ConstValue value {ConstValue::kNull};

    SymbolKind getKind() override;
  };

  class MethodSymbol : public Symbol {
  public:
    /// 参数列表
    List<PTR<Symbol>> params;
    List<PTR<Symbol>> used_symbols;

    SymbolKind getKind() override;
  };

  class EventSymbol : public MethodSymbol {
  public:
    // 事件对应的定义事件
    PTR<MethodSymbol> meta;
    // 是否为类级别事件
    bool is_class_level;

    SymbolKind getKind() override;
  };

  class ClassType : public Type {
  public:
    WPTR<ClassSymbol> symbol;
    // 父类类型
    PTR<Type> super;

    TypeKind getKind() override;
  };

  class ArrayType : public Type {
  public:
    PTR<Type> prefix;
    UInt32 const_size{0};

    TypeKind getKind() override;
  };

  class TypeVariable : public Type {
  public:
    WPTR<TypeVarSymbol> symbol;
    // 最低类型限制，目前只有唯一值：对象
    PTR<Type> lower;

    TypeKind getKind() override;
  };

  /// 模板类型，包含模板原始类型定义和模板实现类型
  /// ClassType中的 symbol 指的是模板类型最终定义的类，每个模板实现类型，都会生成新的ClassSymbol
  class TemplateType : public ClassType {
  public:
    /// 模板原始定义的ClassSymbol，如果是模板原始定义，这里的meta和symbol相同，如果是模板实现则meta和symbol不同
    WPTR<ClassSymbol> meta;
    /// @brief 模板实现参数
    List<PTR<Type>> args;

    TypeKind getKind() override;
  };

  class VariantType : public Type {
  public:
    TypeKind getKind() override;
  };

  class VoidType : public Type {
  public:
    TypeKind getKind() override;
  };

  class NullType : public Type {
  public:
    TypeKind getKind() override;
  };

  template<typename Param, typename Result>
  class SymbolVisitor {
  public:
#define CASE_VISIT_SYMBOL(sym_kind, sym_class) \
  case sym_kind: { \
    const PTR<sym_class> sym = std::static_pointer_cast<sym_class>(symbol); \
    return visit##sym_class(sym, param); \
  }
    Result visitSymbol(const PTR<Symbol>& symbol, Param param) {
      if (symbol == nullptr) {
        if constexpr (std::is_void_v<Result>) {
          return;
        } else {
          return {};
        }
      }
      switch (symbol->getKind()) {
        CASE_VISIT_SYMBOL(SymbolKind::kPackage, PackageSymbol)
        CASE_VISIT_SYMBOL(SymbolKind::kClass, ClassSymbol)
        CASE_VISIT_SYMBOL(SymbolKind::kTypeVar, TypeVarSymbol)
        CASE_VISIT_SYMBOL(SymbolKind::kVariable, VarSymbol)
        CASE_VISIT_SYMBOL(SymbolKind::kMethod, MethodSymbol)
        CASE_VISIT_SYMBOL(SymbolKind::kEvent, EventSymbol)
      default:
        throw std::runtime_error("SymbolVisitor::visitSymbol(): Unknown symbol kind");
      }
    }
#undef CASE_VISIT_SYMBOL
#define VISIT_SYMBOL(sym_class) \
  virtual Result visit ##sym_class(const PTR<sym_class>& symbol, Param param) { \
    if constexpr (std::is_void_v<Result>) { \
      return; \
    } else { \
      return {}; \
    } \
  }
    VISIT_SYMBOL(PackageSymbol)
    VISIT_SYMBOL(ClassSymbol)
    VISIT_SYMBOL(TypeVarSymbol)
    VISIT_SYMBOL(VarSymbol)
    VISIT_SYMBOL(MethodSymbol)
    VISIT_SYMBOL(EventSymbol)
#undef VISIT_SYMBOL
  };

  template<typename Param, typename Result>
  class TypeVisitor {
  public:
#define CASE_VISIT_TYPE(type_kind, type_class) \
  case type_kind: { \
    const PTR<type_class> cast_type = std::static_pointer_cast<type_class>(type); \
    return visit##type_class(cast_type, param); \
  }
    Result visitType(const PTR<Type>& type, Param param) {
      if (type == nullptr) {
        if constexpr (std::is_void_v<Result>) {
          return;
        } else {
          return {};
        }
      }
      switch (type->getKind()) {
        CASE_VISIT_TYPE(TypeKind::kClass, ClassType)
        CASE_VISIT_TYPE(TypeKind::kArray, ArrayType)
        CASE_VISIT_TYPE(TypeKind::kTypeVariable, TypeVariable)
        CASE_VISIT_TYPE(TypeKind::kTemplate, TemplateType)
        CASE_VISIT_TYPE(TypeKind::kVariant, VariantType)
        CASE_VISIT_TYPE(TypeKind::kVoid, VoidType)
        CASE_VISIT_TYPE(TypeKind::kNull, NullType)
      default:
        throw std::runtime_error("TypeVisitor::visitType(): Unknown type kind");
      }
    }
#undef CASE_VISIT_TYPE
#define VISIT_TYPE(type_class) \
  virtual Result visit ##type_class(const PTR<type_class>& type, Param param) { \
    if constexpr (std::is_void_v<Result>) { \
      return; \
    } else { \
      return {}; \
    } \
  }
    VISIT_TYPE(ClassType)
    VISIT_TYPE(ArrayType)
    VISIT_TYPE(TypeVariable)
    VISIT_TYPE(TemplateType)
    VISIT_TYPE(VariantType)
    VISIT_TYPE(VoidType)
    VISIT_TYPE(NullType)
#undef VISIT_TYPE
  };

  /// Symbol比较器，用于比较Symbol内容是否相同
  class SymbolComparator : public SymbolVisitor<const PTR<Symbol>&, bool> {
  public:
    bool areEqualSymbols(const PTR<Symbol>& a, const PTR<Symbol>& b);
    bool areEqualSymbols(const WPTR<Symbol>& a, const WPTR<Symbol>& b);
    bool areEqualSymbols(const List<PTR<Symbol>>& a, const List<PTR<Symbol>>& b);

    bool visitPackageSymbol(const PTR<PackageSymbol>& symbol, const PTR<Symbol>& param) override;
    bool visitClassSymbol(const PTR<ClassSymbol>& symbol, const PTR<Symbol>& param) override;
    bool visitTypeVarSymbol(const PTR<TypeVarSymbol>& symbol, const PTR<Symbol>& param) override;
    bool visitVarSymbol(const PTR<VarSymbol>& symbol, const PTR<Symbol>& param) override;
    bool visitMethodSymbol(const PTR<MethodSymbol>& symbol, const PTR<Symbol>& param) override;
    bool visitEventSymbol(const PTR<EventSymbol>& symbol, const PTR<Symbol>& param) override;
  };

  class TypeReplacer;
  using TypeReplaceMap = HashMap<PTR<TypeVariable>, PTR<Type>>;
  /// Symbol拷贝器，用于拷贝Symbol，并将模板类型参数替换成实际类型
  class SymbolCopier : public SymbolVisitor<const TypeReplaceMap&, PTR<Symbol>> {
  public:
    SymbolCopier();

    template<typename T>
    PTR<T> copySymbol(const PTR<T>& symbol, const TypeReplaceMap& type_replacement) {
      return std::static_pointer_cast<T>(visitSymbol(symbol, type_replacement));
    }

    template<typename T>
    List<PTR<T>> copySymbols(const List<PTR<T>>& symbols, const TypeReplaceMap& type_replacement) {
      List<PTR<T>> result;
      const size_t size = symbols.size();
      for (size_t i = 0; i < size; i++) {
        result.add(copySymbol(symbols[i], type_replacement));
      }
      return result;
    }

    PTR<Symbol> visitPackageSymbol(const PTR<PackageSymbol>& symbol, const TypeReplaceMap& param) override;
    PTR<Symbol> visitClassSymbol(const PTR<ClassSymbol>& symbol, const TypeReplaceMap& param) override;
    PTR<Symbol> visitVarSymbol(const PTR<VarSymbol>& symbol, const TypeReplaceMap& param) override;
    PTR<Symbol> visitMethodSymbol(const PTR<MethodSymbol>& symbol, const TypeReplaceMap& param) override;
    PTR<Symbol> visitEventSymbol(const PTR<EventSymbol>& symbol, const TypeReplaceMap& param) override;
    PTR<Symbol> visitTypeVarSymbol(const PTR<TypeVarSymbol>& symbol, const TypeReplaceMap& param) override;
  private:
    UPTR<TypeReplacer> replacer_;
    PTR<Type> instanceType(const PTR<Type>& target, const TypeReplaceMap& type_replacement) const;
  };

  /// Symbol文本化工具，可将Symbol转化为文本表示
  class SymbolStringifier : public SymbolVisitor<NullValue&, WString> {
  public:
    /// 将Symbol进行文本化
    /// @param symbol 要文本化的Symbol
    /// @return Symbol的文本化唯一标识
    WString stringify(const PTR<Symbol>& symbol);

    WString visitPackageSymbol(const PTR<PackageSymbol>& symbol, NullValue& param) override;
    WString visitClassSymbol(const PTR<ClassSymbol>& symbol, NullValue& param) override;
    WString visitTypeVarSymbol(const PTR<TypeVarSymbol>& symbol, NullValue& param) override;
    WString visitVarSymbol(const PTR<VarSymbol>& symbol, NullValue& param) override;
    WString visitMethodSymbol(const PTR<MethodSymbol>& symbol, NullValue& param) override;
    WString visitEventSymbol(const PTR<EventSymbol>& symbol, NullValue& param) override;
  };

  /// Type比较器，用于检测Type赋值是否正确
  class TypeComparator : public TypeVisitor<const PTR<Type>&, bool> {
  public:
    TypeComparator();
    bool isTypeAssignableFrom(const PTR<Type>& required, const PTR<Type>& assignment);
    bool areTypesAssignableFrom(const List<PTR<Type>>& required, const List<PTR<Type>>& assignment);

    bool visitClassType(const PTR<ClassType>& type, const PTR<Type>& param) override;
    bool visitArrayType(const PTR<ArrayType>& type, const PTR<Type>& param) override;
    bool visitTypeVariable(const PTR<TypeVariable>& type, const PTR<Type>& param) override;
    bool visitTemplateType(const PTR<TemplateType>& type, const PTR<Type>& param) override;
  private:
    UPTR<SymbolComparator> sym_cmp;
  };

  /// 类型替换器，通过传入一个类型替换表，将类型进行替换
  class TypeReplacer : TypeVisitor<const TypeReplaceMap&, PTR<Type>> {
  public:
    PTR<Type> replaceType(const PTR<Type>& type, const TypeReplaceMap& type_replacement);

    PTR<Type> visitClassType(const PTR<ClassType>& type, const TypeReplaceMap& param) override;
    PTR<Type> visitArrayType(const PTR<ArrayType>& type, const TypeReplaceMap& param) override;
    PTR<Type> visitTypeVariable(const PTR<TypeVariable>& type, const TypeReplaceMap& param) override;
    PTR<Type> visitTemplateType(const PTR<TemplateType>& type, const TypeReplaceMap& param) override;
    PTR<Type> visitVariantType(const PTR<VariantType>& type, const TypeReplaceMap& param) override;
    PTR<Type> visitVoidType(const PTR<VoidType>& type, const TypeReplaceMap& param) override;
    PTR<Type> visitNullType(const PTR<NullType>& type, const TypeReplaceMap& param) override;
  };

  /// 模板类型实现的Key生成器，为每个模板实现类型都生成唯一的Key
  class TemplateTypeKeyPrinter : TypeVisitor<std::wstringstream&, void> {
  public:
    /// 获取模板类型实现的唯一key，保证同类型实现参数生成的key是一致的
    /// @param type 模板实现类型
    WString getTypeImplKey(const PTR<TemplateType>& type);

    void visitTemplateType(const PTR<TemplateType>& type, std::wstringstream& param) override;
    void visitClassType(const PTR<ClassType>& type, std::wstringstream& param) override;
    void visitArrayType(const PTR<ArrayType>& type, std::wstringstream& param) override;
    void visitTypeVariable(const PTR<TypeVariable>& type, std::wstringstream& param) override;
    void visitVariantType(const PTR<VariantType>& type, std::wstringstream& param) override;
    void visitVoidType(const PTR<VoidType>& type, std::wstringstream& param) override;
    void visitNullType(const PTR<NullType>& type, std::wstringstream& param) override;
  };

  // =====================================一些常用的过滤函数====================================
  bool kFunc_isMethod(const PTR<Symbol>& symbol);
  bool kFunc_isVariable(const PTR<Symbol>& symbol);
}

#endif //TIEC_SYMBOL_H
